package seph;

//Java
import java.io.*;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

//Minecraft
import net.minecraft.client.Minecraft;
import net.minecraft.src.AchievementList;
import net.minecraft.src.Achievement;
import net.minecraft.src.CommandHandler;
import net.minecraft.src.GameSettings;
import net.minecraft.src.GuiAchievement;
import net.minecraft.src.StatFileWriter;

//Forge
import net.minecraftforge.common.Configuration;
import net.minecraftforge.common.Property;
import net.minecraftforge.common.AchievementPage;

//Forge Mod Loader
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.PreInit;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.client.registry.KeyBindingRegistry;


@Mod(modid="AchievementOptions", name="Achievement options", version="1.2")
public class AchievementOptions {
	
	private String version = "1.2";
	
	@Instance("AchievementOptions")
	public static AchievementOptions instance;
	
	//directory remote stats are saved too
	private static String statsDir;
	
	//Variable to stop writing to the backup file if we are already writing too it
	private static boolean busyWriting = false;
	
	//guiAchievement's private variable that we want to alter
	private static Field achievementTime;
	
	//Minecraft client instance
	private static Minecraft game;
	
	//enable or disable popups
	public static boolean enablePopups;
	
	//list of enabled achievements
	private static ArrayList<AchievementPage> whiteList;
	
	//enable hotkey
	public static boolean enableHotkey;
	
	//advanced options
	public static boolean advancedOptions = false;
	
	//enable filtering
	public static boolean enableFiltering = false;
	
	private static AchievementOptionsConfig config;
	
	public void forceLoad()
	{
		loadConfig(null);
		try {
			load(null);
		}catch (SecurityException e) {
			
		}catch (NoSuchFieldException e){
			
		}
	}
	
	@PreInit
	public void loadConfig(FMLPreInitializationEvent event)
	{
		config = new AchievementOptionsConfig(event.getSuggestedConfigurationFile());
			config.load();
			enablePopups = config.getOrCreateBooleanProperty("popup", Configuration.CATEGORY_GENERAL, false).value.equals("true") ? true : false;
			enableHotkey = config.getOrCreateBooleanProperty("hotkey", Configuration.CATEGORY_GENERAL, true).value.equals("true") ? true : false;
			config.save();
	}
	
	@Init
	public void load(FMLInitializationEvent event) throws SecurityException, NoSuchFieldException
	{
		//save instance of minecraft client
		game = Minecraft.getMinecraft();
		
		//Load stats/achievements from directory
		try
		{
			loadStats();
		} catch (IOException e) {
			//nothing
		}
		
		//Make the timeout variable for achievements public and check if this mod has been installed to the jar
		try {
			achievementTime = this.game.guiAchievement.getClass().getDeclaredField("achievementTime"); //Development
			//achievementTime = this.game.guiAchievement.getClass().getDeclaredField("g"); //Release
				achievementTime.setAccessible(true); //set it to public
				
			Field isModified = this.game.guiAchievement.getClass().getDeclaredField("isModified");
				this.advancedOptions = true;
				System.out.println("Modified GuiAchievements.class detected. Setting Advanced options too: " + advancedOptions);
		}catch (Throwable e) {
			//e.printStackTrace();
		}
		
		//Set a timer to check if the popup is there and reset it if so every 30 milliseconds
		if (!advancedOptions){
			Timer timer = new Timer();
			TimerTask task = new TimerTask(){
				public void run() {
					checkAchievementTimer();
				}
			};
			//Run task, right now, every 30 milliseconds
			timer.scheduleAtFixedRate(task, 0, 30);
		}
		
		//set timer to backup stats and achievements every minute
		Timer backupTimer = new Timer();
		TimerTask backupTask = new TimerTask()
		{
			public void run()
			{
				//System.out.println("Backing up achievements and stats");
				backupStatsAndAchievements();
			}
		};
		backupTimer.scheduleAtFixedRate(backupTask, 60000L, 20000L); //backup every 20 seconds
		
		
		//trigger the "Open inventory" achievement as this one stays on screen until you actually unlock this achievement.
		if (!this.game.statFileWriter.hasAchievementUnlocked(AchievementList.openInventory))
			this.game.statFileWriter.readStat(AchievementList.openInventory, 1);
		
		
		//register key for opening the achievements page
		KeyBindingRegistry.registerKeyBinding(new AchievementKeyHandler(this.game));
		
		
		//atempting shutdown hook again
		Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { backupStatsAndAchievements(); } } ); 
	}
	
	public static void saveSettings()
	{
		//So forge doesnt support custom writing too the config file, but by god im going to do it anyway
		config.categories.get(Configuration.CATEGORY_GENERAL).get("popup").value = new Boolean(enablePopups).toString();
		config.categories.get(Configuration.CATEGORY_GENERAL).get("hotkey").value = new Boolean(enableHotkey).toString();
		config.save();
	}
	
	//Filtering functions
	public static void addToWhitelist(AchievementPage page)
	{
		//check if it already doesnt exist
		if (whiteList.contains(page)) 
			return;
		
		//add =D
		whiteList.add(page); 
	}
	
	public static void removeFromWhitelist(AchievementPage page)
	{
		//Find page
		whiteList.remove(page);
	}
	
	
	private void checkAchievementTimer()
	{
		if (enablePopups) return;
		try {
			achievementTime.setLong(this.game.guiAchievement, 0);
		} catch (IllegalArgumentException e) {
			//e.printStackTrace();
		} catch (IllegalAccessException e) {
			//e.printStackTrace();
		}
	}
	
	public static boolean checkAchievementTrigger(Achievement theAchievement)
	{
		//trigger backup now we have a new achievement
		backupStatsAndAchievements();
		
		//Is achievements enabled
		if (enablePopups) return true;
		
		//Is filtering enabled
		if (enableFiltering)
			for (AchievementPage page : whiteList)
				if (page.isAchievementInPages(theAchievement)) return true; //Let this achievement through
		
		return false;
	}
	
	public static void shutdownHook()
	{
		
	}
	
	//version get
	public String getVersion() { return this.version; }
	
	//load stats and achievements
	private void loadStats() throws IOException
	{
		/*** set vars ***/
		//Get OS
		String os = System.getProperty("os.name");
		//Prefix for directory
		String prefix = System.getProperty("user.home");
		//suffix
		String suffix = ".minecraftstats";
		//Seperator
		String separator = System.getProperty("file.separator");
		
		//Force adding stats to appdata directory in windows (should work with most versions)
		if (os.startsWith("Windows"))
			prefix = System.getenv("APPDATA");
		
		//stats directory
		this.statsDir = prefix + separator + suffix;
		
		//Create the directory if it doesnt already exist
		if (!new File(statsDir).exists())
			new File(statsDir).mkdir();
		
		File input = new File(statsDir + separator + "stats_" + this.game.session.username + "_unsent.data");
		if (input.exists())
		{
			File output = new File(this.game.mcDataDir.getPath() + separator + "stats" + separator + "stats_" + this.game.session.username + "_unsent.dat");
			
			FileReader in = new FileReader(input);
			FileWriter out = new FileWriter(output);
			int c;
			
			while ((c = in.read()) != -1)
				out.write(c);
			
			in.close();
			out.close();
			
			//load new stats
			this.game.statFileWriter = new StatFileWriter(this.game.session, this.game.mcDataDir);
		} else {
			//do a backup now
			backupStatsAndAchievements();
		}
	}
	
	
	private static void backupStatsAndAchievements()
	{
		if (busyWriting) return;
		try {
			busyWriting = true;
			
			File input = new File(game.mcDataDir.getPath() + System.getProperty("file.separator") + "stats" + System.getProperty("file.separator") + "stats_" + game.session.username + "_unsent.dat");
			File output = new File(statsDir + System.getProperty("file.separator") + "stats_" + game.session.username + "_unsent.data");
			
			FileReader in = new FileReader(input);
			FileWriter out = new FileWriter(output);
			int c;
			
			while ((c = in.read()) != -1)
				out.write(c);
			
			in.close();
			out.close();
		} catch (IOException e) {
			
		}
		
		busyWriting = false;
	}
}